package com.googlecode.cswish.test;

import java.lang.reflect.Method;
import java.util.HashMap;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.apache.struts2.StrutsStatics;
import org.junit.After;
import org.junit.Before;

import com.googlecode.cswish.Config;
import com.googlecode.cswish.annotation.Protected;
import com.googlecode.cswish.security.SafeManager;
import com.googlecode.cswish.struts.BaseActionSupport;
import com.googlecode.cswish.struts.spring.BeanIntrospector;
import com.googlecode.cswish.struts.spring.DFactory;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.googlecode.cswish.test.mock.struts2.MockValueStack;
import com.googlecode.cswish.test.mock.struts2.StrutsTestCase;
import com.googlecode.cswish.test.mock.struts2.jsp.StrutsMockHttpServletRequest;
import com.googlecode.cswish.test.mock.struts2.jsp.StrutsMockHttpServletResponse;
import com.googlecode.cswish.test.mock.struts2.jsp.StrutsMockServletContext;
import com.googlecode.cswish.util.FrameConstant;
import com.googlecode.cswish.util.Functions;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.mock.MockActionInvocation;
import com.opensymphony.xwork2.mock.MockActionProxy;
import com.opensymphony.xwork2.util.ValueStack;

/**
 * Wrapper the StrutsTestCase, convert it from JUnit3 to JUnit4
 * 
 * @author Jerry.Feng 2008-11-23
 */
//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations={"classpath*:/applicationContext.xml"})
public class BaseStrutsTestCase extends BaseSpringTestCase {	//AbstractTransactionalDataSourceSpringContextTests

	private final static Logger logger = Logger.getLogger(BaseStrutsTestCase.class);
	
	private static StrutsTestCase instance;

	protected static Container container;
	
	@Resource
	protected DFactory dfactory;
	
	@Resource
	protected BeanIntrospector beanIntrospector;
	
	@Resource
	private Config config;
	
	@Resource
	private Functions functions;
	
	@Before
	public void setUp() {
		if (instance != null) {
			super.setUp();
			return;
		}
		
		instance = new StrutsTestCase();
		instance.setUp();
		container = instance.getContainer();
        StrutsMockServletContext servletContext = new StrutsMockServletContext();
        servletContext.setServletInfo("Jetty");
        servletContext.setContextPath("/");
        ActionContext context = ActionContext.getContext();
        if (context == null) {
            context = new ActionContext(new HashMap());
        }
        context.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
        StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
        request.setupGetServletPath("/");
        request.setupGetRemoteAddr("127.0.0.1");
        context.put(StrutsStatics.HTTP_REQUEST, request);
        context.put(StrutsStatics.HTTP_RESPONSE, new StrutsMockHttpServletResponse());
        context.put(ActionContext.SESSION, new HashMap<String, Object>());
        MockActionInvocation actionInvocation = new MockActionInvocation();
		context.setActionInvocation(actionInvocation);
		context.setParameters(new HashMap<String, Object>());
		ValueStack stack = new MockValueStack(null);
		actionInvocation.setStack(stack);
		actionInvocation.setInvocationContext(context);
        
		MockActionProxy proxy = new MockActionProxy();
		actionInvocation.setProxy(proxy);
		
        objectFactory = ObjectFactory.getInstance();
        container.inject(objectFactory);
        objectFactory.getBean(SafeManager.class, true).setEnablePermissionCheck(false);
        super.setUp();
        
        servletContext.setRealPath(config.getRealWebRootPath());
        stack.getContext().put(FrameConstant.STACK_FUNCTION, functions);
    }
	
	public Class<?> getActionClass(Class<?> serviceClass, String methodName) {
		Method matchedMethod = null;
		if (beanIntrospector.isService(serviceClass.getName()) >= 0)
		{
			matchedMethod = getMethod(serviceClass, methodName);
		} else {
			try {
				serviceClass = objectFactory.getClassInstance(GenericService.class.getName());
				
				matchedMethod = getMethod(serviceClass, methodName);
			} catch (ClassNotFoundException ex) {
				logger.error("Can't find generic service", ex);
			}
		}
		
		String simpleName = beanIntrospector.getSimpleName(serviceClass.getName());
		
		String actionName = beanIntrospector.getActionName(simpleName + '.' + methodName);
		return dfactory.convert2Class(serviceClass, matchedMethod, actionName,
				BaseActionSupport.class, "execute", true, Action.SUCCESS);
	}
	
	protected Method getMethod(Class<?> clazz, String method) {
		Method[] methods = clazz.getDeclaredMethods();
		Method found = null;
		for (Method m : methods) {
			if (m.getAnnotation(Protected.class) == null) {
				if (method.equals(m.getName())) {
					found = m;
					break;
				}
			}
		}
		
		// use DFactory create a new method according to current method interface template
		if (found == null && method.startsWith(FrameConstant.ACTION_PREPARE)) {
			found = getMethod(clazz, 
					method.substring(FrameConstant.ACTION_PREPARE.length()));
		}
		return found;
	}
	
	@After
	public void tearDown() throws Exception {
		super.tearDown();
		//instance.tearDown();
	}
}